#ifndef JANUSCLIENT_H
#define JANUSCLIENT_H

#include <QObject>
#include <QUrl>
#include <QJsonObject>
#include <QJsonDocument>
#include <QTimer>
#include <QString>
#include <QMap>
#include <functional> // for std::function

#include "cwebsocket.h" // 包含 WebSocket 封装类

// 前置声明
class QWebSocket;

class JanusClient : public QObject
{
    Q_OBJECT

public:
    // 定义客户端状态
    enum class State {
        Disconnected,
        ConnectingWebSocket,
        WebSocketConnected, // WebSocket 已连接，等待创建 Session
        CreatingSession,
        SessionActive,      // Session 已建立
        Closing,
        Error
    };
    Q_ENUM(State) // 注册枚举以便在信号/槽中使用

    explicit JanusClient(QObject *parent = nullptr);
    virtual ~JanusClient() override; // 虚析构函数，允许子类正确清理

    // --- 公共接口 ---

    /**
     * @brief 连接到 Janus WebSocket 服务器并尝试建立 Session
     * @param url Janus 服务器的 WebSocket URL (例如 "ws://host:port")
     */
    void connectToServer(const QUrl& url);

    /**
     * @brief 断开与 Janus 服务器的连接（关闭 WebSocket 和销毁 Session）
     */
    void disconnectFromServer();

    /**
     * @brief 获取当前客户端状态
     */
    State getCurrentState() const;

    /**
     * @brief 获取当前 Janus Session ID
     * @return Session ID，如果未激活则返回 -1
     */
    long long getSessionId() const;

    /**
     * @brief 获取最后一次发生的错误信息
     */
    QString getLastError() const;

    /**
     * @brief 发送 JSON 消息到 Janus (通常由子类调用来发送插件特定消息)
     * @param message 要发送的 JSON 对象
     * @param transactionId 可选的事务 ID，用于追踪响应
     * @param handleId 可选的插件句柄 ID
     * @param callback 可选的回调函数，用于处理此事务的特定响应 (success/error/ack)
     * @return 是否成功发送（仅代表 WebSocket 发送成功）
     */
    bool sendMessage(const QJsonObject& message,
                     const QString& transactionId = QString(),
                     long long handleId = -1, // -1 表示消息是针对 Session 而不是 Handle
                     std::function<void(const QJsonObject&)> callback = nullptr);

signals:
    // --- 对外发出的信号 ---

    /**
     * @brief 当客户端状态改变时发出
     * @param newState 新的状态
     */
    void stateChanged(JanusClient::State newState);

    /**
     * @brief 当 Janus Session 成功创建时发出
     * @param sessionId 创建的 Session ID
     */
    void sessionCreated(long long sessionId);

    /**
     * @brief 当与 Janus 的连接（包括 Session）完全断开时发出
     */
    void disconnected();

    /**
     * @brief 当发生错误时发出 (WebSocket 错误或 Janus 报告的错误)
     * @param errorString 错误描述
     */
    void errorOccurred(const QString& errorString);

    /**
     * @brief 当收到需要子类处理的 Janus 事件时发出 (纯虚方法 handleJanusEvent 的信号包装)
     * @param handleId 事件关联的插件句柄 ID
     * @param eventJson 事件的 JSON 内容 (通常在 "plugindata" -> "data" 中)
     */
    void janusEventReceived(long long handleId, const QJsonObject& eventJson);

    /**
     * @brief 当收到需要子类处理的 Janus 插件数据时发出 (纯虚方法 handleJanusPluginData 的信号包装)
     * @param handleId 数据关联的插件句柄 ID
     * @param pluginDataJson 插件数据的 JSON 内容 (通常在 "plugindata" 中，包含 "data" 和可能的 "jsep")
     */
    void janusPluginDataReceived(long long handleId, const QJsonObject& pluginDataJson);

    /**
     * @brief 当收到 JSEP (SDP Offer/Answer) 时发出
     * @param handleId 关联的插件句柄 ID
     * @param jsepJson JSEP 的 JSON 内容 (包含 "type" 和 "sdp")
     */
    void jsepReceived(long long handleId, const QJsonObject& jsepJson);


protected slots:
    // --- 内部用于处理 WebSocket 信号的槽 ---
    virtual void onWebSocketConnected();
    virtual void onWebSocketDisconnected();
    virtual void onWebSocketTextMessageReceived(const QString &message);
    virtual void onWebSocketError(const QString& errorString);

    // --- 内部用于处理 Keepalive 的槽 ---
    virtual void onKeepAliveTimeout();

protected:
    // --- 受保护方法，供子类使用或重写 ---

    /**
     * @brief 生成唯一的事务 ID
     */
    QString generateTransactionId() const;

    /**
     * @brief 处理来自 WebSocket 的已解析的 Janus JSON 消息 (由 onWebSocketTextMessageReceived 调用)
     * @param jsonObject 解析后的 JSON 对象
     */
    virtual void handleJanusMessage(const QJsonObject& jsonObject);

    /**
     * @brief 更新内部状态并发出 stateChanged 信号
     * @param newState 要设置的新状态
     */
    void setState(State newState);

    /**
     * @brief 启动或重置 Keepalive 定时器
     */
    void startKeepAliveTimer();

    /**
     * @brief 停止 Keepalive 定时器
     */
    void stopKeepAliveTimer();

    // --- 纯虚方法，必须由子类实现以处理插件特定的事件和数据 ---

    /**
     * @brief [纯虚] 处理特定于插件的事件 (通常是异步发生的)
     *        例如，在 VideoRoom 中，这可能是用户加入/离开、发布/取消发布等事件。
     * @param handleId 事件关联的插件句柄 ID
     * @param eventJson 事件的 JSON 内容 (通常在 "plugindata" -> "data" 中)
     */
    virtual void handleJanusEvent(long long handleId, const QJsonObject& eventJson){ // = 0

    };

    /**
     * @brief [纯虚] 处理特定于插件的数据，通常是对请求的响应的一部分
     *        例如，VideoRoom 的 "joined" 响应中的参与者列表。
     * @param handleId 数据关联的插件句柄 ID
     * @param pluginDataJson 插件数据的 JSON 内容 (通常在 "plugindata" 中，包含 "data")
     */
    virtual void handleJanusPluginData(long long handleId, const QJsonObject& pluginDataJson){ // = 0

    };

    // --- 成员变量 ---
    CWebSocket* m_websocket;         // WebSocket 客户端实例
    QUrl m_serverUrl;               // 服务器 URL
    State m_currentState;           // 当前状态
    long long m_sessionId;          // Janus Session ID
    QString m_lastError;            // 最后错误信息
    QTimer* m_keepAliveTimer;       // Keepalive 定时器
    // 用于存储待处理事务的回调函数
    QMap<QString, std::function<void(const QJsonObject&)>> m_pendingTransactions;

private:
    // --- 私有方法 ---

    /**
     * @brief 发送创建 Janus Session 的请求
     */
    void sendCreateSessionRequest();

    /**
     * @brief 发送销毁 Janus Session 的请求
     */
    void sendDestroySessionRequest();

    /**
     * @brief 发送 Keepalive 请求
     */
    void sendKeepAliveRequest();

};

#endif // JANUSCLIENT_H
